/*
 * Universidade Estadual de Campinas - UNICAMP
 * MC823 - Laboratório de Redes
 * Alunos:
 *         Daniel Camillo C. Farias  RA: 059878
 *         Vitor Hugo Mickus Rodrigues RA: 072627
 * Professor:
 *         Paulo Lício e Celio
 *
 * Server program for Network Labs. Simulate an ECHO program.
 *
 */

#include "server_echo.h"

/*
 * Main Function, start of the program.
 *      Input:
 *            int argc:  number of parameters passed in command line.
 *            char* argv[]: the parameters passed in command line.
 *      Output:
 *            int : status of the program.             
 */
int main(int argc, char* argv[]) 
{
  // Local Variables
  int sockfd = 0, new_fd = 0;  /* listen on sock_fd, new connection on new_fd */
  int yes = 1, sin_size = 0;
  int numbytes;
  int count_received = 0 , count_chars_received = 0;
  struct sockaddr_in my_addr;    /* my address information */
  struct sockaddr_in their_addr; /* connector's address information */
  char buf[MAXBUFLEN];
  FILE *wsock, *rsock;

  //Create socket descriptor
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }  

  //Something with the socket used... ?? 
  if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1){
    perror("setsockopt (SO_RCVTIMEO)");
    exit(1);
  }  
  
  // Fills struct
  my_addr.sin_family = AF_INET;         /* host byte order */
  my_addr.sin_port = htons(MYPORT);     /* short, network byte order */
  my_addr.sin_addr.s_addr = INADDR_ANY; /* automatically fill with my IP */
  bzero(&(my_addr.sin_zero), 8);        /* zero the rest of the struct */


  // Bind
  if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
    perror("bind");
    exit(1);
  }

  // Listening the port
  if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
  }

  // Main loop
  while( 1 ) {  

    sin_size = sizeof(struct sockaddr_in);

    // Found a connection
    if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1){
      perror("accept");
      continue;
    }

    rsock = fdopen(new_fd, "r");
    wsock = fdopen(new_fd, "w");

    //Print some information
    printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
    
    // Create a child
    switch(fork()) {
    case 0:
      break;
    case -1:
      perror("fork error");
      exit(1);
      break;
    default:  
      // Receive line from client
      while (fgets(buf, MAXBUFLEN, rsock) != NULL) {  
	fflush(rsock);

	numbytes = strlen(buf);

	// Update controls
	count_received++;
	count_chars_received += numbytes;         
      
	//Send line to client
	fputs(buf,wsock);
	fflush(wsock);
      } 
       
      // The client closed a connection
      fprintf(stderr, "Number of reads from %s: %d\n", inet_ntoa(their_addr.sin_addr), count_received);
      fprintf(stderr, "Number of chars from %s: %d\n", inet_ntoa(their_addr.sin_addr), count_chars_received);
      count_received = 0;
      count_chars_received = 0;      

      // Close child connection
      close(new_fd);
      // Child exit
      exit(0);

    }//end of switch
    // close socket
    close(new_fd);
      
  }  
  while(waitpid(-1,NULL,WNOHANG) > 0); /*clean up all child processes*/
}
